﻿using System;
using System.Globalization;

using zijian666.Converts.Abstractions;
using zijian666.Converts.Convertor.Base;
using zijian666.Converts.Core;
using zijian666.Converts.Extensions;

namespace zijian666.Converts.Convertor;

/// <summary>
/// <seealso cref="DateTime" /> 转换器
/// </summary>
public class DateTimeOffsetConvertor : FromConvertor<DateTimeOffset>
                               , IFrom<string, DateTimeOffset>
                               , IFrom<DateTime, DateTimeOffset>
{
    /// <summary>
    /// 日期格式化字符
    /// </summary>
    private static readonly string[] _formats = {
        "HH:mm",
        "HHmmss",
        "HH:mm:ss",
        "yyyyMMdd",
        "yyyy/MM/dd",
        "yyyy-MM-dd",
        "yyyy.MM.dd",
        "yyyyMMddHHmmss",
        "yyyyMMddHHmmssfff",
        "yyyy-MM-dd HH:mm:ss",
        "yyyyMMddHHmmssffffff" ,
        "yyyy-MM-dd HH:mm:ss:fff",
        "yyyy-MM-dd HH:mm:ss.fff",
        "yyyy-MM-dd HH:mm:ss:ffffff" ,
        "yyyy-MM-dd HH:mm:ss.ffffff" , };

    /// <inheritdoc/>
    public ConvertResult<DateTimeOffset> From(IConvertContext context, string input)
    {
        var s = input.Trim();
        if (DateTimeOffset.TryParse(s, out var result))
        {
            return result;
        }
        foreach (var format in _formats)
        {
            if (input.Length == format.Length)
            {
                if (DateTimeOffset.TryParseExact(s, format, null, DateTimeStyles.None, out result))
                {
                    return result;
                }
                break;
            }
            if (input.Length == format.Length + (" +08:00").Length)
            {
                if (DateTimeOffset.TryParseExact(s, format + " zzz", null, DateTimeStyles.None, out result))
                {
                    return result;
                }
                break;
            }
        }
        return context.ConvertFail(this, input);
    }

    /// <inheritdoc/>
    public ConvertResult<DateTimeOffset> From(IConvertContext context, DateTime input) => new (input);

}
